import { Dep } from "./dep.mjs";

export class Watcher {
    constructor(vm, key, cb, options) {
        this.vm = vm;
        this.key = key;
        this.cb = cb;
        this.getter = parse(key);
        if (options) {
            this.deep = options.deep;
        }
        this.value = this.get();
    }
    get() {
        Dep.target = this;
        const value = this.getter(this.vm);
        if (this.deep) {
            traverse(value)
        }
        Dep.target = null;
        return value;
    }
    update() {
        const oldVal = this.value;
        const value = this.get();
        this.value = value;
        if (oldVal !== value || Array.isArray(value) || this.deep) {
            this.cb.call(this.vm, value, oldVal);
        }
    }
}

function parse(keyStr) {
    const keys = keyStr.split('.');
    return function (obj) {
        for (const key of keys) {
            if (obj) {
                obj = obj[key];
            }
        }
        return obj;
    }
}

function traverse(val) {
    if (typeof val !== 'object' || val === null) {
        return;
    }
    if (Array.isArray(val)) {
        for (let i = 0; i < val.length; i++) {
            traverse(val[i]);
        }
    } else {
        const keys = Object.keys(val);
        for (const key of keys) {
            traverse(val[key]);
        }
    }
}